package com.cocolover2.andbase.utils;

import android.content.Context;
import android.view.View;
import android.view.inputmethod.InputMethodManager;

import java.lang.reflect.Field;

/**
 * Created by liubo on 7/19/16.
 *
 * @since 1.1.1
 */
public class BugFixUtil {

//    /**
//     * Fix for https://code.google.com/p/android/issues/detail?id=171190 .
//     * <p/>
//     * When a view that has focus gets detached, we wait for the main thread to be idle and then
//     * check if the InputMethodManager is leaking a view. If yes, we tell it that the decor view got
//     * focus, which is what happens if you press home and come back from recent apps. This replaces
//     * the reference to the detached view with a reference to the decor view.
//     * <p/>
//     * Should be called from {@link Activity#onCreate(android.os.Bundle)} )}.
//     */
//    public static void fixFocusedViewLeak(Application application) {
//
//        // Don't know about other versions yet.
//        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1 || Build.VERSION.SDK_INT > 23) {
//            return;
//        }
//
//        final InputMethodManager inputMethodManager =
//                (InputMethodManager) application.getSystemService(Context.INPUT_METHOD_SERVICE);
//
//        final Field mServedViewField;
//        final Field mHField;
//        final Method finishInputLockedMethod;
//        final Method focusInMethod;
//        try {
//            mServedViewField = InputMethodManager.class.getDeclaredField("mServedView");
//            mServedViewField.setAccessible(true);
//            mHField = InputMethodManager.class.getDeclaredField("mServedView");
//            mHField.setAccessible(true);
//            finishInputLockedMethod = InputMethodManager.class.getDeclaredMethod("finishInputLocked");
//            finishInputLockedMethod.setAccessible(true);
//            focusInMethod = InputMethodManager.class.getDeclaredMethod("focusIn", View.class);
//            focusInMethod.setAccessible(true);
//        } catch (NoSuchFieldException e) {
//            Log.e("IMMLeaks", "Unexpected reflection exception", e);
//            return;
//        } catch (NoSuchMethodException e) {
//            Log.e("IMMLeaks", "Unexpected reflection exception", e);
//            return;
//        }
////        catch (NoSuchMethodException | NoSuchFieldException unexpected) {
////            Log.e("IMMLeaks", "Unexpected reflection exception", unexpected);
////            return;
////        }
//
//        application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
//            @Override
//            public void onActivityDestroyed(Activity activity) {
//
//            }
//
//            @Override
//            public void onActivityStarted(Activity activity) {
//
//            }
//
//            @Override
//            public void onActivityResumed(Activity activity) {
//
//            }
//
//            @Override
//            public void onActivityPaused(Activity activity) {
//
//            }
//
//            @Override
//            public void onActivityStopped(Activity activity) {
//
//            }
//
//            @Override
//            public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
//
//            }
//
//            @Override
//            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
//                ReferenceCleaner cleaner = new ReferenceCleaner(inputMethodManager, mHField, mServedViewField,
//                        finishInputLockedMethod);
//                View rootView = activity.getWindow().getDecorView().getRootView();
//                ViewTreeObserver viewTreeObserver = rootView.getViewTreeObserver();
//                viewTreeObserver.addOnGlobalFocusChangeListener(cleaner);
//            }
//        });
//    }
//
//    static class ReferenceCleaner
//            implements MessageQueue.IdleHandler, View.OnAttachStateChangeListener,
//            ViewTreeObserver.OnGlobalFocusChangeListener {
//
//        private final InputMethodManager inputMethodManager;
//        private final Field mHField;
//        private final Field mServedViewField;
//        private final Method finishInputLockedMethod;
//
//        ReferenceCleaner(InputMethodManager inputMethodManager, Field mHField, Field mServedViewField,
//                         Method finishInputLockedMethod) {
//            this.inputMethodManager = inputMethodManager;
//            this.mHField = mHField;
//            this.mServedViewField = mServedViewField;
//            this.finishInputLockedMethod = finishInputLockedMethod;
//        }
//
//        @Override
//        public void onGlobalFocusChanged(View oldFocus, View newFocus) {
//            if (newFocus == null) {
//                return;
//            }
//            if (oldFocus != null) {
//                oldFocus.removeOnAttachStateChangeListener(this);
//            }
//            Looper.myQueue().removeIdleHandler(this);
//            newFocus.addOnAttachStateChangeListener(this);
//        }
//
//        @Override
//        public void onViewAttachedToWindow(View v) {
//        }
//
//        @Override
//        public void onViewDetachedFromWindow(View v) {
//            v.removeOnAttachStateChangeListener(this);
//            Looper.myQueue().removeIdleHandler(this);
//            Looper.myQueue().addIdleHandler(this);
//        }
//
//        @Override
//        public boolean queueIdle() {
//            clearInputMethodManagerLeak();
//            return false;
//        }
//
//        private void clearInputMethodManagerLeak() {
//            try {
//                Object lock = mHField.get(inputMethodManager);
//                // This is highly dependent on the InputMethodManager implementation.
//                synchronized (lock) {
//                    View servedView = (View) mServedViewField.get(inputMethodManager);
//                    if (servedView != null) {
//
//                        boolean servedViewAttached = servedView.getWindowVisibility() != View.GONE;
//
//                        if (servedViewAttached) {
//                            // The view held by the IMM was replaced without a global focus change. Let's make
//                            // sure we get notified when that view detaches.
//
//                            // Avoid double registration.
//                            servedView.removeOnAttachStateChangeListener(this);
//                            servedView.addOnAttachStateChangeListener(this);
//                        } else {
//                            // servedView is not attached. InputMethodManager is being stupid!
//                            Activity activity = extractActivity(servedView.getContext());
//                            if (activity == null || activity.getWindow() == null) {
//                                // Unlikely case. Let's finish the input anyways.
//                                finishInputLockedMethod.invoke(inputMethodManager);
//                            } else {
//                                View decorView = activity.getWindow().peekDecorView();
//                                boolean windowAttached = decorView.getWindowVisibility() != View.GONE;
//                                if (!windowAttached) {
//                                    finishInputLockedMethod.invoke(inputMethodManager);
//                                } else {
//                                    decorView.requestFocusFromTouch();
//                                }
//                            }
//                        }
//                    }
//                }
//            } catch (IllegalAccessException e) {
//                Log.e("IMMLeaks", "Unexpected reflection exception", e);
//            } catch (InvocationTargetException e) {
//                Log.e("IMMLeaks", "Unexpected reflection exception", e);
//            }
//        }
//
//        private Activity extractActivity(Context context) {
//            while (true) {
//                if (context instanceof Application) {
//                    return null;
//                } else if (context instanceof Activity) {
//                    return (Activity) context;
//                } else if (context instanceof ContextWrapper) {
//                    Context baseContext = ((ContextWrapper) context).getBaseContext();
//                    // Prevent Stack Overflow.
//                    if (baseContext == context) {
//                        return null;
//                    }
//                    context = baseContext;
//                } else {
//                    return null;
//                }
//            }
//        }
//    }

    /**
     * 修复软键盘导致的内存泄漏
     *
     * @param destContext
     */
    public static void fixInputMethodManagerLeak(Context destContext) {
        if (destContext == null) {
            return;
        }

        InputMethodManager imm = (InputMethodManager) destContext.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm == null) {
            return;
        }

        String[] arr = new String[]{"mCurRootView", "mServedView", "mNextServedView"};
        Field f = null;
        Object obj_get = null;
        for (int i = 0; i < arr.length; i++) {
            String param = arr[i];
            try {
                f = imm.getClass().getDeclaredField(param);
                if (!f.isAccessible()) {
                    f.setAccessible(true);
                } // author: sodino mail:sodino@qq.com
                obj_get = f.get(imm);
                if (obj_get != null && obj_get instanceof View) {
                    View v_get = (View) obj_get;
                    if (v_get.getContext() == destContext) {
                        f.set(imm, null);
                    } else {
                        break;
                    }
                }
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
    }
}
